package com.sjd.mall.service.goods.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sjd.common.core.domain.AjaxResult;
import com.sjd.mall.domain.SjdAccountDO;
import com.sjd.mall.domain.SjdGoodsDO;
import com.sjd.mall.domain.SjdGoodsTypeDO;
import com.sjd.mall.domain.dto.goods.*;
import com.sjd.mall.mapper.SjdGoodsMapper;
import com.sjd.mall.mapper.SjdGoodsTypeMapper;
import com.sjd.mall.service.account.AccountService;
import com.sjd.mall.service.goods.GoodsDiscountService;
import com.sjd.mall.service.goods.GoodsService;
import com.sjd.wx.utils.ThirdSessionHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;

import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author : Mr.s
 * @version : 1.0
 * @description : 商品service
 * @date : 2022-01-11 11:00
 */
@Slf4j
@Service
public class GoodsServiceImpl implements GoodsService {

    @Autowired
    private RedisTemplate<String, String> stringRedisTemplate;

    @Autowired
    private SjdGoodsMapper sjdGoodsMapper;

    @Autowired
    private SjdGoodsTypeMapper sjdGoodsTypeMapper;

    @Autowired
    private AccountService accountService;

    @Autowired
    private GoodsDiscountService goodsDiscountService;

    private static final String SJD_GOODS_BANNER = "sjd:goods:banner";

    /**
     * 获取所有未删除的商品
     *
     * @param requestDTO requestDTO
     * @return return
     */
    @Override
    public List<SjdWebSiteGoodsQueryResponseDTO> queryGoodsWebSite(SjdWebSiteGoodsQueryRequestDTO requestDTO) {
        List<SjdWebSiteGoodsQueryResponseDTO> responseDTOList = sjdGoodsMapper.queryGoodsWebSite(requestDTO.getGoodsId(), requestDTO.getGoodsName(),
                requestDTO.getGoodsTypeId(), requestDTO.getIsOnline(), requestDTO.getIsCanRefund(), requestDTO.getTypeClass());
        if (CollectionUtils.isNotEmpty(responseDTOList)){
            responseDTOList.forEach(responseDTO -> {
                if (responseDTO.getTypeClass()==2) {
                    BigDecimal sold = BigDecimal.ZERO;
                    BigDecimal subtract = responseDTO.getGoodsTotal().subtract(responseDTO.getGoodsStorage());
                    if (subtract.compareTo(BigDecimal.ZERO) > 0) {
                        sold = subtract;
                    }
                    responseDTO.setGoodsSold(sold);
                }
            });
        }
        return responseDTOList;
    }

    /**
     * 查询商品 根据id查询接口
     *
     * @param goodsId goodsId
     * @return return
     */
    @Override
    public AjaxResult queryGoodsWebSiteByGoodsId(Long goodsId) {
        SjdWebSiteGoodsQueryResponseDTO responseDTO = null;
        SjdWebSiteGoodsQueryRequestDTO requestDTO = new SjdWebSiteGoodsQueryRequestDTO();
        requestDTO.setGoodsId(goodsId);
        List<SjdWebSiteGoodsQueryResponseDTO> sjdWebSiteGoodsQueryResponseDTOS = queryGoodsWebSite(requestDTO);
        if (CollectionUtils.isNotEmpty(sjdWebSiteGoodsQueryResponseDTOS)) {
            responseDTO = sjdWebSiteGoodsQueryResponseDTOS.get(0);
        }
        return AjaxResult.success(responseDTO);
    }

    /**
     * 商品增加
     *
     * @param requestDTO request
     * @return return
     */
    @Override
    public AjaxResult addGoods(SjdGoodsAddRequestDTO requestDTO) {

        SjdGoodsDO sjdGoodsDO = SjdGoodsDO.builder()
                .goodsName(requestDTO.getGoodsName())
                .goodsTypeId(requestDTO.getGoodsTypeId())
                .goodsPrice(requestDTO.getGoodsPrice())
                .goodsStorage(requestDTO.getGoodsStorage())
                .goodsTips(requestDTO.getGoodsTips())
                .goodsDetail(requestDTO.getGoodsDetail())
                .bigPicture(requestDTO.getBigPicture())
                .isCanRefund(requestDTO.getIsCanRefund())
                .isCanComment(requestDTO.getIsCanComment())
                .isOnline(requestDTO.getIsOnline())
                .creatorId(requestDTO.getCreatorId())
                .goodsPicture(requestDTO.getGoodsPicture())
                .build();
        //课程操作
        SjdGoodsTypeDO sjdGoodsTypeDO = sjdGoodsTypeMapper.selectByPrimaryKey(requestDTO.getGoodsTypeId());
        if (sjdGoodsTypeDO != null) {
            if (sjdGoodsTypeDO.getTypeClass() == 2) {
                //课程计划总人数
                sjdGoodsDO.setGoodsTotal(requestDTO.getGoodsStorage());
            }
        }
        sjdGoodsMapper.insertSelective(sjdGoodsDO);
        return AjaxResult.success();
    }

    /**
     * 更新商品
     *
     * @param requestDTO request
     * @return return
     */
    @Override
    public synchronized AjaxResult updateGoods(SjdGoodsUpdateRequestDTO requestDTO) {
        SjdGoodsDO sjdGoodsDO = SjdGoodsDO.builder()
                .goodsId(requestDTO.getGoodsId())
                .goodsName(requestDTO.getGoodsName())
                .goodsPrice(requestDTO.getGoodsPrice())
                .goodsTypeId(requestDTO.getGoodsTypeId())
                .goodsStorage(requestDTO.getGoodsStorage())
                .goodsTips(requestDTO.getGoodsTips())
                .goodsDetail(requestDTO.getGoodsDetail())
                .bigPicture(requestDTO.getBigPicture())
                .isOnline(requestDTO.getIsOnline())
                .isCanRefund(requestDTO.getIsCanRefund())
                .isCanComment(requestDTO.getIsCanComment())
                .goodsPicture(requestDTO.getGoodsPicture())
                .build();
        //课程特殊处理
        SjdGoodsTypeDO sjdGoodsTypeDO = sjdGoodsTypeMapper.selectByPrimaryKey(requestDTO.getGoodsTypeId());
        if (sjdGoodsTypeDO != null && requestDTO.getGoodsTotal() != null) {
            if (sjdGoodsTypeDO.getTypeClass() == 2) {
                SjdGoodsDO oirDO = sjdGoodsMapper.selectByPrimaryKey(requestDTO.getGoodsId());

                //现在总数与数据库的总数的差
                BigDecimal subtract = requestDTO.getGoodsTotal().subtract(oirDO.getGoodsTotal());
                //修改剩余可报名人数
                sjdGoodsDO.setGoodsStorage(subtract.add(sjdGoodsDO.getGoodsStorage()));
                //修改课程计划总人数
                sjdGoodsDO.setGoodsTotal(requestDTO.getGoodsStorage());
            }
        }
        sjdGoodsMapper.updateByPrimaryKeySelective(sjdGoodsDO);
        return AjaxResult.success();
    }


    /**
     * 上下线商品
     *
     * @param goodsId  id
     * @param isOnline isOnline
     * @return return
     */
    @Override
    public AjaxResult onlineOfflineGoods(Long goodsId, boolean isOnline) {
        SjdGoodsDO updateDO = new SjdGoodsDO();
        updateDO.setGoodsId(goodsId);
        updateDO.setIsOnline(isOnline);
        //上下线均删除在banner，下线后本就不该在banner中
        updateDO.setIsBanner(false);
        sjdGoodsMapper.updateByPrimaryKeySelective(updateDO);

        if (isOnline) {
            return AjaxResult.success();
        }
        //下架删除banner
        String bannerJson = stringRedisTemplate.opsForValue().get(SJD_GOODS_BANNER);
        JSONArray jsonArray = JSONArray.parseArray(bannerJson);
        boolean needInsert = false;
        if (jsonArray != null) {
            List<JSONObject> jsonObjects = jsonArray.toJavaList(JSONObject.class);
            Iterator<JSONObject> iterator = jsonObjects.iterator();
            while (iterator.hasNext()) {
                JSONObject jsonObject = iterator.next();
                Long rGoodsId = jsonObject.getLong("goodsId");
                if (goodsId.equals(rGoodsId)) {
                    iterator.remove();
                    needInsert = true;
                    break;
                }
            }
            if (needInsert) {
                bannerJson = JSONObject.toJSONString(jsonObjects);
                stringRedisTemplate.opsForValue().set(SJD_GOODS_BANNER, bannerJson);
            }
        }
        return AjaxResult.success();
    }

    /**
     * 删除商品
     *
     * @param goodsId goodsId
     * @return return
     */
    @Override
    public AjaxResult deleteGoods(Long goodsId) {
        sjdGoodsMapper.deleteByPrimaryKey(goodsId);
        return AjaxResult.success();
    }

    /**
     * 获取在线商品列表 小程序
     *
     * @param requestDTO requestDTO
     * @return return
     */
    @Override
    public List<SjdGetGoodsListResponseDTO> getGoodsList(SjdGetGoodsListRequestDTO requestDTO) {
        List<SjdGetGoodsListResponseDTO> responseDTOList = new ArrayList<>(32);

        List<SjdGoodsDO> goodsDOList = sjdGoodsMapper.queryGoodsApp(requestDTO.getGoodsId(), null, requestDTO.getGoodsTypeId(), true, null, requestDTO.getTypeClass());
        for (SjdGoodsDO sjdGoodsDO : goodsDOList) {
            SjdGetGoodsListResponseDTO responseDTO = SjdGetGoodsListResponseDTO.builder()
                    .goodsId(sjdGoodsDO.getGoodsId())
                    .goodsName(sjdGoodsDO.getGoodsName())
                    .bigPicture(sjdGoodsDO.getBigPicture())
                    .goodsPicture(sjdGoodsDO.getGoodsPicture())
                    .goodsTips(sjdGoodsDO.getGoodsTips())
                    .goodsDetail(sjdGoodsDO.getGoodsDetail())
                    .goodsPrice(sjdGoodsDO.getGoodsPrice())
                    .goodsStorage(sjdGoodsDO.getGoodsStorage())
                    .isCanComment(sjdGoodsDO.getIsCanComment())
                    .isCanRefund(sjdGoodsDO.getIsCanRefund())
                    .build();
            Long userId = ThirdSessionHolder.getSjdMemberId();
            if (userId != null) {
                responseDTO.setMembershipPrice(getMembershipPrice(userId, sjdGoodsDO.getGoodsPrice()));
            }
            responseDTOList.add(responseDTO);
        }
        return responseDTOList;
    }


    /**
     * 获取商品信息 调取用户模块 实现会员价功能 小程序
     *
     * @param id id
     * @return return
     */
    @Override
    public Object getGoodsInfo(Long id) {
        SjdGoodsDO sjdGoodsDO = sjdGoodsMapper.selectByPrimaryKey(id);
        SjdGetGoodsListResponseDTO responseDTO = SjdGetGoodsListResponseDTO.builder()
                .goodsId(sjdGoodsDO.getGoodsId())
                .goodsName(sjdGoodsDO.getGoodsName())
                .bigPicture(sjdGoodsDO.getBigPicture())
                .goodsPicture(sjdGoodsDO.getGoodsPicture())
                .goodsTips(sjdGoodsDO.getGoodsTips())
                .goodsDetail(sjdGoodsDO.getGoodsDetail())
                .goodsPrice(sjdGoodsDO.getGoodsPrice())
                .goodsStorage(sjdGoodsDO.getGoodsStorage())
                .isCanComment(sjdGoodsDO.getIsCanComment())
                .build();
        return AjaxResult.success(responseDTO);
    }

    /**
     * 添加商品到banner
     *
     * @param goodsId goodsId
     * @return return
     */
    @Override
    public AjaxResult addBanner(@RequestParam(name = "goodsId") Long goodsId) {
        String bannerJson = stringRedisTemplate.opsForValue().get(SJD_GOODS_BANNER);
        JSONArray jsonArray = JSONArray.parseArray(bannerJson);
        if (jsonArray == null) {
            jsonArray = new JSONArray();
        }
        JSONObject jsonObject = new JSONObject();
        SjdGoodsDO sjdGoodsDO = sjdGoodsMapper.selectByPrimaryKey(goodsId);
        if (sjdGoodsDO == null) {
            return AjaxResult.error("请刷新重试");
        }
        if (!sjdGoodsDO.getIsOnline()) {
            return AjaxResult.error("所选商品已下架，请上架后重试");
        }
        if (sjdGoodsDO.getIsBanner()) {
            return AjaxResult.success("所属商品已在banner中");
        }
        String bigPicture = sjdGoodsDO.getBigPicture();
        jsonObject.put("goodsId", goodsId);
        jsonObject.put("bigPicture", bigPicture);
        jsonArray.add(jsonObject);
        String resultJson = jsonArray.toJSONString();
        stringRedisTemplate.opsForValue().set(SJD_GOODS_BANNER, resultJson);
        changeDbBanner(goodsId, true);
        return AjaxResult.success();
    }

    /**
     * 添加商品到banner
     *
     * @param goodsId goodsId
     * @return return
     */
    @Override
    public AjaxResult removeBanner(Long goodsId) {
        String bannerJson = stringRedisTemplate.opsForValue().get(SJD_GOODS_BANNER);
        JSONArray jsonArray = JSONArray.parseArray(bannerJson);
        if (jsonArray == null) {
            return AjaxResult.error("请刷新重试");
        }
        List<JSONObject> jsonObjects = jsonArray.toJavaList(JSONObject.class);
        Iterator<JSONObject> iterator = jsonObjects.iterator();
        while (iterator.hasNext()) {
            JSONObject next = iterator.next();
            if (goodsId.equals(next.getLong("goodsId"))) {
                iterator.remove();
                break;
            }
        }
        String resultJson = JSONObject.toJSONString(jsonObjects);
        stringRedisTemplate.opsForValue().set(SJD_GOODS_BANNER, resultJson);
        changeDbBanner(goodsId, false);
        return AjaxResult.success();
    }

    /**
     * 初始化banner
     */
    @Override
    public void initBanner() {
        log.warn("初始化banner...");
        List<SjdGoodsDO> isBannerGoods = sjdGoodsMapper.getIsBannerGoods();
        JSONArray jsonArray = new JSONArray();
        isBannerGoods.stream().forEach(sjdGoodsDO -> {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("goodsId", sjdGoodsDO.getGoodsId());
            jsonObject.put("bigPicture", sjdGoodsDO.getBigPicture());
            jsonArray.add(jsonObject);
        });
        String resultJson = jsonArray.toJSONString();
        stringRedisTemplate.opsForValue().set(SJD_GOODS_BANNER, resultJson);
        log.warn("初始化banner结束");
    }

    /**
     * 获取banner redis实现 小程序
     *
     * @return return
     */
    @Override
    public List<JSONObject> getBanner() {
        String bannerJson = stringRedisTemplate.opsForValue().get(SJD_GOODS_BANNER);
        JSONArray jsonArray = JSONArray.parseArray(bannerJson);
        if (jsonArray == null) {
            return new ArrayList<>();
        }
        return jsonArray.toJavaList(JSONObject.class);
    }

    /**
     * 设置banner redis实现  管理后台
     *
     * @param goodsIds ids
     * @return return
     */
    @Override
    public AjaxResult setBanner(List<Long> goodsIds) {
        //清空
        sjdGoodsMapper.clearAllBanner();
        JSONArray jsonArray = new JSONArray();
        for (Long id : goodsIds) {
            JSONObject jsonObject = new JSONObject();
            SjdGoodsDO sjdGoodsDO = sjdGoodsMapper.selectByPrimaryKey(id);
            if (sjdGoodsDO == null) {
                return AjaxResult.error("请刷新重试");
            }
            System.out.println(sjdGoodsDO.getGoodsId() + "---" + sjdGoodsDO.getIsOnline());
            if (!sjdGoodsDO.getIsOnline()) {
                return AjaxResult.error("商品已下架,id:" + sjdGoodsDO.getGoodsId() + "商品名称:" + sjdGoodsDO.getGoodsName());
            }
            String bigPicture = sjdGoodsDO.getBigPicture();
            jsonObject.put("goodsId", id);
            jsonObject.put("bigPicture", bigPicture);
            jsonArray.add(jsonObject);
        }
        stringRedisTemplate.opsForValue().set(SJD_GOODS_BANNER, jsonArray.toJSONString());
        for (Long id : goodsIds) {
            changeDbBanner(id, true);
        }
        return AjaxResult.success();
    }

    /**
     * 减少库存
     *
     * @param goodsId   goodId
     * @param changeNum changeNum
     * @return MutablePair<Boolean result, String msg>
     */
    @Override
    public MutablePair<Boolean, String> decreaseStorage(@NotNull Long goodsId, @NotNull BigDecimal changeNum) {
        BigDecimal realChangeNum = changeNum.negate();
        MutablePair<Boolean, String> mutablePair = changeStorage(goodsId, realChangeNum);
        if (!mutablePair.left) {
            log.warn("减库存异常-" + mutablePair.right);
        }
        return mutablePair;
    }

    /**
     * 增加库存
     *
     * @param goodsId   goodsId
     * @param changeNum changeNum
     * @return return
     */
    @Override
    public MutablePair<Boolean, String> increaseStorage(@NotNull Long goodsId, @NotNull BigDecimal changeNum) {
        BigDecimal realChangeNum = changeNum.negate();
        MutablePair<Boolean, String> mutablePair = changeStorage(goodsId, realChangeNum);
        if (!mutablePair.left) {
            log.warn("加库存异常-" + mutablePair.right);
        }
        return mutablePair;
    }

    /**
     * 修改库存
     *
     * @param goodsId   goodsId
     * @param changeNum sChangeNum
     * @return return
     */
    private synchronized MutablePair<Boolean, String> changeStorage(Long goodsId, BigDecimal changeNum) {
        MutablePair<Boolean, String> mutablePair = new MutablePair<>(false, "修改库存异常:");

        // 小于0 即 减库存
        if (BigDecimal.ZERO.compareTo(changeNum) > 0) {
            SjdGoodsDO sjdGoodsDO = sjdGoodsMapper.selectByPrimaryKey(goodsId);
            if (sjdGoodsDO == null) {
                mutablePair.right += ("商品" + goodsId + "不存在");
                return mutablePair;
            }
            //库存小于购买量 防止超卖
            if (sjdGoodsDO.getGoodsStorage().compareTo(changeNum) < 0) {
                mutablePair.right += ("商品库存不足,减库存数:" + changeNum + ",库存当前剩余:" + sjdGoodsDO.getGoodsStorage());
                return mutablePair;
            }
        }
        //变量不小于0,通用操作
        //开始操作数据库
        int i = sjdGoodsMapper.updateStorage(goodsId, changeNum);
        if (i > 0) {
            return new MutablePair<>(Boolean.TRUE, "");
        }
        return mutablePair;
    }

    /**
     * 获取会会员价格
     *
     * @param memberId   memberId
     * @param goodsPrice goodsPrice
     * @return return
     */
    @Override
    public BigDecimal getMembershipPrice(Long memberId, BigDecimal goodsPrice) {
        SjdAccountDO accountByMemberId = accountService.findAccountByMemberId(memberId);
        Integer memberLevel = accountByMemberId.getMemberLevel();
        BigDecimal goodsDiscount = goodsDiscountService.getGoodsDiscount(memberLevel);
        if (goodsDiscount == null) {
            goodsDiscount = new BigDecimal("1.0");
        }
        return goodsDiscount.multiply(goodsPrice).setScale(2, RoundingMode.UP);
    }

    /**
     * 修改数据库banner
     *
     * @param goodsId goodsId
     * @param flag    flag true-加 false-删除
     */
    public void changeDbBanner(Long goodsId, Boolean flag) {
        SjdGoodsDO sjdGoodsDO = new SjdGoodsDO();
        sjdGoodsDO.setGoodsId(goodsId);
        sjdGoodsDO.setIsBanner(flag);
        sjdGoodsMapper.updateByPrimaryKeySelective(sjdGoodsDO);
    }
}
